//
// Created by yunnan xu on 2020/11/22.
//

#ifndef ANDROIDGRAPHICSDEMOS_SCENE_H
#define ANDROIDGRAPHICSDEMOS_SCENE_H

#include <memory>
#include "Singleton.h"
#include "tinyxml2.h"
#include <unordered_map>
#include <string>
#include <vector>
#include "glm.hpp"
#include "ext.hpp"

class IRenderItem;
class Camera;
class ParticleSystem;

namespace Phy {
    class PhyScene;
}

class Scene {

public:

    Scene(const char * scene_file_path);
    std::shared_ptr<Camera> GetMainCamera() const;

    void ParseScene();
    void Update(double elapsed_time, double tot_time);

    glm::vec3 GetLightPos(int index) const;
    glm::mat4 GetLightMatrix(int index) const;

    std::shared_ptr<IRenderItem> GetSkyboxItem();
    void SetSkyboxItem(std::shared_ptr<IRenderItem> item);
    double GetElapsedTime() const {return tick_elapsed_time;}

    std::vector<std::shared_ptr<IRenderItem>>::const_iterator GetOpaqueItemBegin() const;
    std::vector<std::shared_ptr<IRenderItem>>::const_iterator GetOpaqueItemEnd() const;

    std::vector<std::shared_ptr<IRenderItem>>::const_iterator GetInstancedItemBegin() const;
    std::vector<std::shared_ptr<IRenderItem>>::const_iterator GetInstancedItemEnd() const;

    std::vector<std::shared_ptr<IRenderItem>>::const_iterator GetSkinnedMeshItemBegin() const;
    std::vector<std::shared_ptr<IRenderItem>>::const_iterator GetSkinnedMeshItemEnd() const;

    std::vector<std::string>::const_iterator GetPassListBegin() const;
    std::vector<std::string>::const_iterator GetPassListEnd() const;

private:

    std::shared_ptr<Camera> mainCamera;
    tinyxml2::XMLDocument xmlDoc;

    std::vector<std::shared_ptr<IRenderItem>> opaqueItemList;
    std::vector<std::shared_ptr<IRenderItem>> instanceItemList;
    std::vector<std::shared_ptr<IRenderItem>> skinnedMeshItemList;

    std::shared_ptr<IRenderItem> skyboxItem;
    std::vector<std::string> passNameList;
    std::vector<glm::vec3> lightList;

    std::shared_ptr<Phy::PhyScene> phyScene;
    std::shared_ptr<ParticleSystem> particleSystem;

    double tick_elapsed_time{};

    void ParseCamera(tinyxml2::XMLElement * element);
    void ParseOpaqueItems(tinyxml2::XMLElement * element);
    void ParsePassList(tinyxml2::XMLElement * element);
    void ParseInstancedItem(tinyxml2::XMLElement * element);

    static void ParseMesh(tinyxml2::XMLElement * element, const char * & mesh_type, const char * & mesh_name);
    static void ParseTexture(tinyxml2::XMLElement * element, const char * & texture_name);
};


class SceneMgr : public Singleton<SceneMgr>
{
public:
    std::shared_ptr<Scene> GetCurrentScene();
    void LoadScene(const char * scene_file_path);

private:
    std::shared_ptr<Scene> currentScene;
};


#endif //ANDROIDGRAPHICSDEMOS_SCENE_H
